Skip to content

Conversation

@WSQS
Copy link
Owner

@WSQS WSQS commented Nov 14, 2025

Summary by CodeRabbit

  • Refactor
    • Improved graphics pipeline initialization for more direct shader updates and rendering flow.
    • Lazy window acquisition with automatic creation and cleanup to stabilize GUI and texture handling.
    • Streamlined pipeline wrapper encapsulation and lifecycle to simplify resource management and reduce indirection.

@coderabbitai
Copy link

coderabbitai bot commented Nov 14, 2025

Walkthrough

Centralized window lifecycle in GpuWrapper via lazy acquire_window(); made PipelineWrapper non-copyable and moved its constructor to private; replaced optional pipeline and removed raw SDL_Window* from UserApp, updating main.cpp to use concrete PipelineWrapper and gpu_wrapper->acquire_window() calls.

Changes

Cohort / File(s) Change Summary
GPU wrapper / window management
sdl_wrapper/sdl_wrapper.gpu.ixx
Added acquire_window() for lazy window creation/claiming; added SDL_video.h include; destructor releases GPU window and destroys it; get_texture_format() now uses acquire_window().
Pipeline wrapper interface
sdl_wrapper/sdl_wrapper.pipeline.ixx
Moved PipelineWrapper(std::shared_ptr<GpuWrapper>) out of public (now private); removed defaulted copy/move ctors; kept public ~PipelineWrapper(), data(), submit().
Application integration
main.cpp
Removed SDL_Window* window field and its create/release logic; changed pipeline_wrapper from std::optional<sopho::PipelineWrapper> to concrete sopho::PipelineWrapper; updated all pipeline and texture calls to use direct pipeline methods and gpu_wrapper->acquire_window() where window handle was required; removed explicit window release on quit.

Sequence Diagram(s)

sequenceDiagram
    participant App as UserApp
    participant Gpu as GpuWrapper
    participant Pipe as PipelineWrapper
    participant SDL as SDL/GPU

    App->>Gpu: create GpuWrapper(shared_ptr)
    App->>Pipe: construct PipelineWrapper(Gpu)   %% direct concrete construction
    App->>Pipe: set_vertex_shader(src)
    App->>Gpu: acquire_window()
    alt first acquire
        Gpu->>SDL: SDL_CreateWindow()
        Gpu->>SDL: SDL_ClaimWindowForGPUDevice()
        Gpu->>Gpu: store m_window
    end
    Gpu-->>App: window handle
    App->>Gpu: get_texture_format(window)  %% uses acquire_window internally
    App->>Pipe: submit()
    Pipe->>SDL: submit pipeline to GPU
    App->>App: shutdown
    Pipe->>SDL: pipeline teardown
    Gpu->>SDL: SDL_ReleaseWindowFromGPUDevice()
    Gpu->>SDL: SDL_DestroyWindow()
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Verify GpuWrapper::acquire_window() is thread-safe (if required) and handles repeated calls without leaks.
  • Confirm that PipelineWrapper being non-copyable and having a private constructor still allows intended construction (factory or friend usage) and that no call sites rely on copy/move.
  • Check all main.cpp call-site conversions from optional (->) to concrete (.) for correctness and that no null/empty-state paths remain.
  • Ensure destructor ordering and lifetime of GpuWrapper and PipelineWrapper avoid use-after-free during shutdown.

Possibly related PRs

  • Fix resource leak #10 — also modifies window lifecycle and GPU device binding; strongly related to centralizing or changing window acquire/release calls.
  • GL Edit #6 — changes UserApp graphics members and pipeline/window handling; directly related to pipeline type and window field changes.
  • fix: clean up code #21 — alters graphics pipeline creation/management patterns; related to PipelineWrapper usage and pipeline instantiation changes.

Poem

🐰 I hopped through code with nimble paws,

A window found its cozy cause.
The pipeline stands, no optional shade,
Private doors close on copy trade.
I nibble bugs and hum — rebuild hooray! 🎋

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Window wrapper' accurately reflects the main changes: introducing a window management system via GpuWrapper.acquire_window() and removing manual window handling from UserApp.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch window-wrapper

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e22d918 and 62decd7.

📒 Files selected for processing (1)
  • sdl_wrapper/sdl_wrapper.gpu.ixx (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • sdl_wrapper/sdl_wrapper.gpu.ixx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: build (windows-latest, Debug, clang)
  • GitHub Check: build (windows-latest, Release, cl)
  • GitHub Check: build (windows-latest, Debug, cl)
  • GitHub Check: build (windows-latest, Release, clang)
  • GitHub Check: build (windows-latest, Debug, clang)
  • GitHub Check: build (windows-latest, Release, gcc)
  • GitHub Check: build (windows-latest, Debug, gcc)
  • GitHub Check: build (Debug, clang)
  • GitHub Check: build (Debug, gcc)
  • GitHub Check: build (Release, gcc)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

This commit fixes the style issues introduced in 88be7ac according to the output
from ClangFormat.

Details: #24
@deepsource-io
Copy link
Contributor

deepsource-io bot commented Nov 14, 2025

Here's the code health analysis summary for commits a8e0b57..62decd7. View details on DeepSource ↗.

Analysis Summary

AnalyzerStatusSummaryLink
DeepSource C & C++ LogoC & C++❌ Failure
❗ 8 occurences introduced
🎯 94 occurences resolved
View Check ↗

💡 If you’re a repository administrator, you can configure the quality gates from the settings.

@github-actions
Copy link

clang-tidy review says "All clean, LGTM! 👍"

1 similar comment
@github-actions
Copy link

clang-tidy review says "All clean, LGTM! 👍"

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
main.cpp (1)

28-28: Concrete PipelineWrapper member simplifies usage; ensure copy/move semantics are as intended

Switching from an optional to a concrete sopho::PipelineWrapper constructed via gpu_wrapper->create_pipeline() and then using it directly in init()/iterate() is a nice simplification—no more has_value()/-> indirection and the pipeline is always initialized before use.

Given that PipelineWrapper is returned by value from GpuWrapper::create_pipeline() and owns GPU resources, this pattern relies on the copy/move behavior of PipelineWrapper. To avoid surprises, it’s worth aligning this with the suggestion in sdl_wrapper/sdl_wrapper.pipeline.ixx (explicitly delete copies and, if needed, enable moves) and then ensuring you don’t inadvertently copy pipeline_wrapper elsewhere.

Once you lock down those semantics in the wrapper type, the usage here is straightforward and robust.

Also applies to: 74-76, 154-154, 163-163, 195-195

🧹 Nitpick comments (4)
sdl_wrapper/sdl_wrapper.gpu.ixx (2)

8-8: Window member and teardown ordering look good; add a small guard for robustness

The added SDL_Window* m_window plus inclusion of the video header and the destructor’s order of operations (release-from-device, then destroy window, then destroy device) are all sensible and keep window/device lifetimes consistent.

To be a bit more defensive in failure cases (e.g. device creation failed but a window was somehow created later), consider guarding the release call on m_device as well, mirroring the later if (m_device):

        ~GpuWrapper()
        {
            if (m_window)
            {
-                SDL_ReleaseWindowFromGPUDevice(m_device, m_window);
+                if (m_device)
+                {
+                    SDL_ReleaseWindowFromGPUDevice(m_device, m_window);
+                }
                 SDL_DestroyWindow(m_window);
            }
            if (m_device)
            {
                SDL_DestroyGPUDevice(m_device);
            }
            m_device = nullptr;
        }

This keeps behavior unchanged in the normal path while avoiding calling SDL with a null device pointer in edge cases.

Also applies to: 19-21, 31-37


74-82: Tighten acquire_window() API surface (return by value instead of non-const reference)

acquire_window() currently returns a non-const reference to the internal SDL_Window*, which lets callers accidentally reassign m_window and break invariants inside GpuWrapper.

You can keep behavior identical while tightening encapsulation by returning the pointer by value:

-        auto& acquire_window()
+        SDL_Window* acquire_window()
         {
             if (!m_window)
             {
                 m_window = SDL_CreateWindow("Hello, Triangle!", 960, 540, SDL_WINDOW_RESIZABLE);
                 SDL_ClaimWindowForGPUDevice(m_device, m_window);
             }
             return m_window;
         }

Call sites that currently pass gpu_wrapper->acquire_window() to SDL/ImGui APIs will continue to compile unchanged.

sdl_wrapper/sdl_wrapper.pipeline.ixx (1)

29-40: Constructor access restriction is good; consider making PipelineWrapper explicitly non-copyable (or move-only)

Making the PipelineWrapper(std::shared_ptr<GpuWrapper>) constructor private and friending GpuWrapper nicely centralizes pipeline creation in the GPU wrapper.

However, with only a user-defined destructor and no explicit copy/move declarations, PipelineWrapper is still copyable by default while move operations are suppressed. If PipelineWrapper owns the SDL_GPUGraphicsPipeline* and releases it in the destructor, accidental copies could lead to subtle lifetime issues.

Consider making ownership explicit, e.g.:

    class PipelineWrapper
    {
        SDL_GPUGraphicsPipeline* m_graphics_pipeline{};
        std::shared_ptr<GpuWrapper> m_device{};
        // ...

        bool m_modified = false;

        PipelineWrapper(std::shared_ptr<GpuWrapper> p_device);
    public:
+       PipelineWrapper(const PipelineWrapper&) = delete;
+       PipelineWrapper& operator=(const PipelineWrapper&) = delete;
+
+       PipelineWrapper(PipelineWrapper&&) = default;
+       PipelineWrapper& operator=(PipelineWrapper&&) = default;

This keeps construction restricted to GpuWrapper while preventing accidental copies and allowing move semantics if you need them later.

main.cpp (1)

104-104: Good use of acquire_window(); consider also using GpuWrapper::get_texture_format()

Routing ImGui and swapchain acquisition through gpu_wrapper->acquire_window() nicely reflects the new window ownership model in GpuWrapper and avoids carrying a raw SDL_Window* in UserApp.

Since GpuWrapper now exposes get_texture_format(), you can also avoid duplicating the device+window pairing logic when setting init_info.ColorTargetFormat:

-        ImGui_ImplSDL3_InitForSDLGPU(gpu_wrapper->acquire_window());
-        ImGui_ImplSDLGPU3_InitInfo init_info = {};
-        init_info.Device = gpu_wrapper->data();
-        init_info.ColorTargetFormat =
-            SDL_GetGPUSwapchainTextureFormat(gpu_wrapper->data(), gpu_wrapper->acquire_window());
+        ImGui_ImplSDL3_InitForSDLGPU(gpu_wrapper->acquire_window());
+        ImGui_ImplSDLGPU3_InitInfo init_info = {};
+        init_info.Device = gpu_wrapper->data();
+        init_info.ColorTargetFormat = gpu_wrapper->get_texture_format();

The later SDL_WaitAndAcquireGPUSwapchainTexture(commandBuffer, gpu_wrapper->acquire_window(), ...) call already cleanly uses the wrapper, so this keeps all swapchain/window handling consistently funneled through GpuWrapper.

Also applies to: 107-108, 171-172

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a8e0b57 and e22d918.

📒 Files selected for processing (3)
  • main.cpp (6 hunks)
  • sdl_wrapper/sdl_wrapper.gpu.ixx (4 hunks)
  • sdl_wrapper/sdl_wrapper.pipeline.ixx (1 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.gpu.ixx:73-76
Timestamp: 2025-11-14T00:45:09.377Z
Learning: In sdl_wrapper/sdl_wrapper.gpu.ixx, validation for m_window in the GpuWrapper::get_texture_formate() method (checking if m_window is nullptr before calling SDL_GetGPUSwapchainTextureFormat) is deferred to a future window wrapper implementation and should not be flagged in reviews.
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.gpu.ixx:37-43
Timestamp: 2025-11-13T11:35:48.273Z
Learning: In sdl_wrapper/sdl_wrapper.gpu.ixx, null pointer validation for the GpuWrapper::create_buffer method (checking m_device, SDL_CreateGPUBuffer return value, and shared_from_this() validity) is deferred to a future issue and should not be flagged in reviews.
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.buffer.ixx:0-0
Timestamp: 2025-11-13T11:34:32.714Z
Learning: In sdl_wrapper/sdl_wrapper.buffer.ixx, null pointer validation for the BufferWrapper constructor (checking p_gpu, p_gpu->data(), and SDL_CreateGPUBuffer return value) is deferred to a future issue and should not be flagged in reviews.
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.gpu.ixx:0-0
Timestamp: 2025-11-13T02:58:26.859Z
Learning: The sdl_wrapper library (in the repository WSQS/sdl_test) does not allow throwing exceptions. Error handling must use return codes, validity checks, or other non-exception mechanisms.
📚 Learning: 2025-11-14T00:45:09.377Z
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.gpu.ixx:73-76
Timestamp: 2025-11-14T00:45:09.377Z
Learning: In sdl_wrapper/sdl_wrapper.gpu.ixx, validation for m_window in the GpuWrapper::get_texture_formate() method (checking if m_window is nullptr before calling SDL_GetGPUSwapchainTextureFormat) is deferred to a future window wrapper implementation and should not be flagged in reviews.

Applied to files:

  • main.cpp
  • sdl_wrapper/sdl_wrapper.pipeline.ixx
  • sdl_wrapper/sdl_wrapper.gpu.ixx
📚 Learning: 2025-11-13T11:35:48.273Z
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.gpu.ixx:37-43
Timestamp: 2025-11-13T11:35:48.273Z
Learning: In sdl_wrapper/sdl_wrapper.gpu.ixx, null pointer validation for the GpuWrapper::create_buffer method (checking m_device, SDL_CreateGPUBuffer return value, and shared_from_this() validity) is deferred to a future issue and should not be flagged in reviews.

Applied to files:

  • main.cpp
  • sdl_wrapper/sdl_wrapper.pipeline.ixx
  • sdl_wrapper/sdl_wrapper.gpu.ixx
📚 Learning: 2025-11-13T11:34:32.714Z
Learnt from: WSQS
Repo: WSQS/sdl_test PR: 7
File: sdl_wrapper/sdl_wrapper.buffer.ixx:0-0
Timestamp: 2025-11-13T11:34:32.714Z
Learning: In sdl_wrapper/sdl_wrapper.buffer.ixx, null pointer validation for the BufferWrapper constructor (checking p_gpu, p_gpu->data(), and SDL_CreateGPUBuffer return value) is deferred to a future issue and should not be flagged in reviews.

Applied to files:

  • main.cpp
  • sdl_wrapper/sdl_wrapper.pipeline.ixx
  • sdl_wrapper/sdl_wrapper.gpu.ixx
🔇 Additional comments (1)
sdl_wrapper/sdl_wrapper.gpu.ixx (1)

84-87: get_texture_format() correctly funnels through acquire_window()

Routing get_texture_format() through acquire_window() ensures a window is created/claimed on first use before querying the swapchain texture format, which matches the new ownership model.

No behavioral issues here from the wrapper’s perspective.

@coderabbitai
Copy link

coderabbitai bot commented Nov 14, 2025

Note

Unit test generation is an Early Access feature. Expect some limitations and changes as we gather feedback and continue to improve it.


Generating unit tests... This may take up to 20 minutes.

@coderabbitai
Copy link

coderabbitai bot commented Nov 14, 2025

Caution

The CodeRabbit agent failed during execution: Clone operation failed

@github-actions
Copy link

clang-tidy review says "All clean, LGTM! 👍"

@WSQS WSQS merged commit 005e202 into dev Nov 14, 2025
23 of 24 checks passed
@WSQS WSQS deleted the window-wrapper branch November 14, 2025 08:04
@coderabbitai coderabbitai bot mentioned this pull request Nov 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants